package main

import (
	"log"
	"sync"
	"time"
)

/**
WRLock锁
WRLock和Mutex都是线程锁，WRLock将数据读取/写入的锁分开，多个协程读取同一个数据不是互斥的，可以同时进行数据读取，
只有当多协程写同一个Lock数据，才是互斥的才会启动数据锁机制，比Mutex锁的性能要更好。
*/
func main() {
	//非线程安全操作
	//AddCount()
	//安全操作
	//AddCountAnquan()
	//安全和等待锁
	AddCountAnquanWait()

}

// WaitGroup等待的好处就是可以自己结束不用人为进行休眠操作
func AddCountAnquanWait() {
	count := 0
	var syAdd sync.Mutex
	var syWait sync.WaitGroup
	for i := 0; i < 5000; i++ {
		//告诉WaitGroup 新加了一个协程任务
		syWait.Add(1)
		//go开始新协程完成任务
		go func() {
			//次数对于协程变量上锁
			defer func() {
				//变量解锁
				syAdd.Unlock()
				//协程解锁
				syWait.Done()
			}()
			syAdd.Lock()
			count++
			//从1到5000的增加
			log.Println("count=", count)
		}()
	}
	//告诉waitGroup 需要在此处等待group 协程
	syWait.Wait()
	//结果5000,每次结果相同
	println(count)
}

//线程安全操作就是共享内存的变量上锁
func AddCountAnquan() {
	count := 0
	var syAdd sync.Mutex
	for i := 0; i < 5000; i++ {
		//开启多协程进行count累计
		go func() {
			//次数对于协程变量上锁
			defer func() {
				syAdd.Unlock()
			}()
			syAdd.Lock()
			count++
			//从1到5000的增加
			log.Println("count=", count)
		}()
	}
	//主线程休眠1秒
	time.Sleep(1 * time.Second)
	//结果5000,每次结果相同
	println(count)
}

//非安全线程操作
func AddCount() {
	count := 0
	for i := 0; i < 50000; i++ {
		//开启多协程进行count累计
		go func() {
			count++
		}()
	}
	//主线程休眠1秒
	time.Sleep(1 * time.Second)
	//结果并非5000,每次结果不相同
	println(count)
}
